package com.comven.example.utils;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;

import java.math.BigInteger;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;


@Slf4j
public enum JsonTools {
    /**
     * 默认、通用
     */
    INS(false),
    /**
     * 带有class、支持泛型等序列化
     */
    SERIALIZER(true);

    private ObjectMapper objectMapper;

    /**
     * 构造方法
     *
     * @param isClass 是否包含class
     */
    JsonTools(boolean isClass) {
        objectMapper = new ObjectMapper();
        // Include.NON_NULL 属性为NULL 不序列化
        objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // 忽略 在json字符串中存在，但是在java对象中不存在对应属性的情况。防止错误
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        // 允许出现特殊字符和转义符
        objectMapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // 允许出现单引号
        objectMapper.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // javaTime字段序列化 使java8 localDate生效自定义转为timestamps形式
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDateTime.class, new DateJsonSerializer.LocalDateTimeSerializer());
        javaTimeModule.addDeserializer(LocalDateTime.class, new DateJsonSerializer.LocalDateTimeDeserializer());
        javaTimeModule.addSerializer(LocalDate.class, new DateJsonSerializer.LocalDateSerializer());
        javaTimeModule.addDeserializer(LocalDate.class, new DateJsonSerializer.LocalDateDeserializer());
        javaTimeModule.addSerializer(Date.class, new DateJsonSerializer.DateSerializer());
        javaTimeModule.addDeserializer(Date.class, new DateJsonSerializer.DateDeserializer());
        javaTimeModule.addSerializer(Timestamp.class, new DateJsonSerializer.TimestampSerializer());
        javaTimeModule.addDeserializer(Timestamp.class, new DateJsonSerializer.TimestampDeserializer());
        javaTimeModule.addSerializer(new ToStringSerializer(Long.TYPE));
        javaTimeModule.addSerializer(new ToStringSerializer(Double.TYPE));
        javaTimeModule.addSerializer(new ToStringSerializer(Float.TYPE));
        javaTimeModule.addSerializer(new ToStringSerializer(BigInteger.class));

        objectMapper.registerModule(javaTimeModule);
        //枚举类型序列化方式，默认情况下使用Enum.name()。自定义使用WRITE_ENUMS_USING_INDEX
        objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);
        // Date统一转换timestamps形式
        objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true);
        // 忽略空Bean转json的错误
        objectMapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
        // 属性可视化，PropertyAccessor支持的类型有 ALL,CREATOR,FIELD,GETTER,IS_GETTER,NONE,SETTER, --Visibility所有已实现的接口
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //将在序列化的json中添加类型信息
        if (isClass) {
            objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                    ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        }
    }

    public ObjectMapper getObjectMapper() {
        return objectMapper;
    }

    public <T> String toJsonString(T value) {
        try {
            return objectMapper.writeValueAsString(value);
        } catch (Exception e) {
            log.error("", e);
            return null;
        }
    }

    public byte[] toValueBytes(Object value) {
        try {
            return objectMapper.writeValueAsBytes(value);
        } catch (Exception e) {
            log.error("", e);
            return null;
        }
    }

    public <T> T toObject(String json, Class<T> clazz) {
        try {
            return objectMapper.readValue(json, clazz);
        } catch (Exception e) {
            log.error("readValue error :{}", json, e);
            return null;
        }
    }

    public <T> T toObject(byte[] bytes, Class<T> clazz) {
        try {
            return this.objectMapper.readValue(bytes, 0, bytes.length, clazz);
        } catch (Exception e) {
            log.error("readValue error :{}", new String(bytes), e);
            return null;
        }
    }

    public <T> List<T> toList(byte[] bytes, Class<T> clazz) {
        if (bytes == null) {
            return null;
        }
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, clazz);
            return objectMapper.readValue(bytes, javaType);
        } catch (Exception e) {
            log.error("", e);
            return null;
        }
    }

    public <T> List<T> toList(String str, Class<T> clazz) {
        if (str == null) {
            return null;
        }
        try {
            JavaType javaType = objectMapper.getTypeFactory().constructParametricType(List.class, clazz);
            return objectMapper.readValue(str, javaType);
        } catch (Exception e) {
            log.error("", e);
            return null;
        }
    }

}
